<template>
  <div class="deploy">
    <div class="cardTop">训练模型</div>
    <el-card class="elCard">
      <div class="left">
        <ul class="leftUl">
          <li :class="changeClass" class="leftLi">
            <div class="circle">
              <img src="../../assets/image/圆圈.svg" alt="" />
            </div>
            <div v-if="!isChat" class="text">基础信息</div>
            <div v-if="isChat" class="chatImg">
              <img src="../../assets/image//机器人.png" alt="" srcset="" />
            </div>
          </li>

          <li class="leftLi1-5">
            <div class="circle">
              <img src="../../assets/image/圆圈.svg" alt="" />
            </div>
            <div v-if="!isChat" class="text">训练日志</div>
            <div v-if="isChat" class="chatImg">
              <img src="../../assets/image//信息2.png" alt="" srcset="" />
            </div>
          </li>

          <li class="leftLi2">
            <div class="circle">
              <img src="../../assets/image/圆圈.svg" alt="" />
            </div>
            <div class="text">还没有模型?</div>
            <div class="textBottom" @click="mouseupHandle()">
              <img :src="isCreate ? xiala2 : xiala" alt="" />
              快速创建模型
            </div>
          </li>
          <li class="leftLi3" :class="changeClass">
            <div class="circle3">
              <img src="../../assets/image/圆圈.svg" alt="" />
            </div>
          </li>
        </ul>
      </div>
      <div class="elForm">
        <el-form
          :model="tableData"
          :rules="rules"
          label-width="120px"
          ref="formRef"
        >
          <el-form-item label="选择训练模式" prop="cont_name">
            <el-select
              v-model="form.drillPattern"
              placeholder="请选择训练模式"
              @change="handleChange"
            >
              <el-option
                v-for="(item, index) in my_container_name"
                :key="index"
                :label="item"
                :value="item"
              />
            </el-select>
          </el-form-item>
          <div class="conent">
            <!-- 折线echarts区域 -->
            <div class="echartsLine" :class="changeEchartsline">
              <div id="myLineEcharts"></div>
            </div>

            <!-- echarts区域 -->
            <div class="echarts" :class="changeEcharts">
              <div id="myEcharts"></div>
            </div>

            <!-- 日志区域 -->
            <div class="logs" :class="changeLogs">
              <el-scrollbar height="500px">
                <!-- 系统的logs区域 -->
                <div
                  v-for="(message, index) in messages"
                  :key="index"
                  class="echartsMsg"
                >
                  {{ message }}
                </div>

                <!-- 人工的聊天区域 -->
                <div class="chat" v-if="isChat">
                  <chat></chat>
                </div>
              </el-scrollbar>
            </div>
          </div>

          <!-- 高级选项 -->
          <div class="high" v-if="isHighShow">
            <el-button type="primary" large @click="toCreate" class="toCreate"
              >快速创建模型</el-button
            >
          </div>
          <el-form-item class="elButton" v-if="!isHighShow && !isChat">
            <el-button type="primary" @click="onSubmit">开始训练</el-button>
            <el-button type="primary" @click="cancel">开始训练测试版</el-button>
            <el-button @click="cancel1">停止训练测试版</el-button>
            <el-button @click="closeWebSocket">停止训练</el-button>
            <!-- <el-button @click="connectWebSocket">开始训练</el-button> -->
          </el-form-item>
        </el-form>
      </div>
    </el-card>
  </div>
</template>

<script setup>
import {
  ElButton,
  ElForm,
  ElFormItem,
  ElSelect,
  ElOption,
  ElScrollbar,
  ElCard
} from 'element-plus'
import { ref, reactive, computed, onUnmounted, onMounted, nextTick } from 'vue'
import { beginDrill, listDeploy } from '../../api/model.js'
import xiala2 from '../../assets/image/上拉.png'
import xiala from '../../assets/image/下拉.png'
import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
import io from 'socket.io-client'
// import { VueNativeSock } from 'vue-native-websocket-vue3'

import chat from '../../views/chat/chat.vue'

const router = useRouter()
const formRef = ref(null)

const isHighShow = ref(false) // 还没有模型?显示
const isCreate = ref(false) // 下拉图片切换
const isChat = ref(false) // 人工模式

const echartsData = ref([]) // echarts中的数据,应该切换成epoch
const lossData = ref([]) //websocket返回lossData
const newArray = ref([]) // 删除了前俩个数据的echartsData

let currentIndex = 0 // 当前数据索引
let timer // 定时器
let chartInstance //echarts实例

let currentIndex1 = 0 // 当前折线图数据索引
let timer1 // 定时器
let chartInstance1 //echarts实例

const echartsShow = ref(false)
const logsShow = ref(false)

const my_container_name = ref(['系统训练', '人工训练'])

const form = ref({
  cont_name: 'hyy126.10.20',
  drillPattern: '系统训练',
  image: '',
  model: ''
})

const ws = ref(null)
const messages = ref([])

//  原websocket
const connectWebSocket = async () => {
  ws.value = new WebSocket(
    `ws://192.168.11.222:5533/train_logs/${form.value.cont_name}`
  )
  ws.timeout = 50000000000
  ws.value.onopen = () => {
    console.log('WebSocket已连接')
  }

  ws.value.onmessage = async event => {
    await nextTick() // 等待DOM更新完成
    const messageElements = document.getElementsByClassName('echartsMsg')
    const lastMessageElement = messageElements[messageElements.length - 1]
    if (lastMessageElement) {
      lastMessageElement.scrollIntoView({ behavior: 'smooth', block: 'end' })
    }
    console.log('event.data', event.data)
    messages.value.push(event.data)
    const logContent = event.data // 日志文件内容

    const epochPattern = /'epoch':\s*(\d+\.\d+)/g // epoch正则表达式
    let match = epochPattern.exec(logContent)
    while (match !== null) {
      const epoch = match[1] // 匹配到的epoch值
      echartsData.value.push(epoch)
      newArray.value = echartsData.value.slice(2)
      newArray.value.pop()
      console.log('epoch', epoch)
      console.log('echartsData.value', echartsData.value)
      match = epochPattern.exec(logContent)
    }

    const lossPattern = /'loss':\s*(\d+\.\d+)/g // loss正则表达式
    let match2 = lossPattern.exec(logContent)
    while (match2 !== null) {
      const loss = match2[1] // 匹配到的loss值
      lossData.value.push(loss)
      console.log('loss', loss)
      console.log('lossData.value', lossData.value)
      match2 = lossPattern.exec(logContent)
    }

    if (
      echartsData.value.length > 0 &&
      parseFloat(echartsData.value[0]) !== 0
    ) {
      echartsShow.value = true
    }

    if (lossData.value.length > 0 && parseFloat(lossData.value[0]) !== 0) {
      echartsShow.value = true
    }

    initChart()
    initChartLine()
  }

  ws.value.onclose = event => {
    console.log('WebSocket已断开', event)
  }
  ws.value.onerror = error => {
    console.error('WebSocket出错', error)
  }
}

const closeWebSocket = () => {
  if (ws.value) {
    ws.value.close()
    messages.value = []
  }
}

// logs宽度变化
const changeLogs = computed(() => {
  if (logsShow.value) {
    return 'logs isCreateTrue'
  } else {
    return 'logs'
  }
})

// 选择训练模式
const handleChange = () => {
  if (form.value.drillPattern === '人工训练') {
    isChat.value = true
  } else {
    isChat.value = false
  }
}

const tableData = reactive([
  {
    creat_time: '2023-05-03',
    container_name: 'Tom',
    image_name: 'https://mirrors.aliyun.com/'
  }
])

//左侧 还没有模型? 显示事件
const mouseupHandle = () => {
  isCreate.value = !isCreate.value
  isHighShow.value = !isHighShow.value
}

//左侧 还没有模型? 显示事件
const changeClass = computed(() => {
  if (isCreate.value) {
    return 'leftLi isCreateTrue'
  } else {
    return 'leftLi'
  }
})

// 点击echarts显示
const changeEcharts = computed(() => {
  if (echartsShow.value) {
    return 'echarts isEchartsTrue'
  } else {
    return 'echarts'
  }
})

// 点击折线echarts显示
const changeEchartsline = computed(() => {
  if (echartsShow.value) {
    return 'echarts isEchartsLineTrue'
  } else {
    return 'echarts'
  }
})

// 开始训练测试版
const cancel = () => {
  echartsShow.value = true
  logsShow.value = true
  timer = setInterval(initChart, 1000)

  connectWebSocket()
}

// 停止训练测试版
const cancel1 = () => {
  closeWebSocket()
  echartsShow.value = false
  logsShow.value = true
  clearInterval(timer)
  // currentIndex = logsData[logsData.length - 1].value // 将 currentIndex 重置为当前数字的值
  timer = setInterval(initChart, 1000)
}

const rules = reactive({
  cont_name: [{ required: true, message: '请输入正确的模型', trigger: 'blur' }]
})

const toCreate = () => {
  router.push('./create')
}

onMounted(() => {
  // fetchData()
  initChart()
  initChartLine()
})

// 开始训练
const onSubmit = async () => {
  console.log('form.cont_name', form.value.cont_name)
  // const valid = await formRef.value.validate()
  // if (valid) {
  let msgData = {
    // cont_name: form.value.cont_name,
    imgname: 'llama0.82',
    cont_name: form.value.cont_name,
    path_to_llama_model: '/src/openbuddy-openllama-7b-v5-fp16',
    model_type: 'llama',
    output_dir: '/output',
    output_path: `/nvme1/ningyu/lang_output/${form.value.cont_name}`,
    logs_path: '/nvme1/ningyu/langport_logs',
    finetuning_type: 'lora',
    dataset_location: 'oaast_sft_zh',
    dataset_info: '',
    gpu_nums: '1',
    deepspeed_type: '1'
  }
  beginDrill(msgData)
    .then(res => {
      // 处理请求成功的响应
      console.log('这是开始训练的res', res)

      echartsShow.value = true
      logsShow.value = true
      timer = setInterval(initChart, 1000)

      setTimeout(() => {
        connectWebSocket()
      }, 5000)
    })
    .catch(error => {
      // 处理请求错误
      console.error(error)
    })
  // } else {
  //   console.log('训练的表单数据不完整')
  // }
}

// 计算百分比
function getPct (index) {
  const epoch = echartsData.value[index]

  console.log('计算百分比里的epoch', epoch)

  if (epoch === '2.98') {
    return '100%'
  } else if (isNaN(parseFloat(epoch))) {
    return '20%'
  } else {
    const pct = (parseFloat(epoch) / 3) * 80 + 20
    return pct.toFixed(1) + '%'
  }
}

function initChart () {
  if (echartsShow.value === false) {
    // 当 echartsData 的长度为 0 时，直接停止定时器
    clearInterval(timer)
    echartsData.value.push('0')
    return
  } else {
    if (currentIndex >= echartsData.value.length) {
      // 达到最后一个数据时停止定时器
      clearInterval(timer)
      return
    }

    const chartDom = document.getElementById('myEcharts')
    if (chartInstance) {
      // 在初始化图表之前，可能已经存在一个使用相同 DOM 元素的图表实例 , 会报警告"[ECharts] There is a chart instance already initialized on the dom."
      chartInstance.dispose()
    }

    chartInstance = echarts.init(chartDom)

    const titleText =
      currentIndex === echartsData.length - 1 ? '训练已完成' : `已完成了`

    // 现在的长条形
    chartInstance.setOption({
      title: [
        {
          text: titleText,
          x: 'center',
          top: '35%',
          left: '25%',
          textStyle: {
            color: '#FFFFFF',
            fontSize: 16,
            fontWeight: '300'
          }
        },
        {
          text: getPct(currentIndex),
          x: 'center',
          top: '8%',
          textStyle: {
            fontSize: '50',
            color: '#FFFFFF',
            fontFamily: 'DINAlternate-Bold, DINAlternate',
            fontWeight: '600'
          }
        }
      ],
      xAxis: {
        type: 'value',
        show: false,
        max: 100
      },
      yAxis: {
        type: 'category',
        show: true,
        axisLabel: {
          show: false
        },
        axisLine: {
          show: false
        },
        axisTick: {
          show: false
        }
      },
      series: [
        {
          name: '',
          type: 'bar',
          barWidth: 50,
          barCategoryGap: '50%',
          showBackground: true,
          backgroundStyle: {
            color: 'rgba(66, 66, 66, .3)',
            borderRadius: [40, 40, 40, 40] // 设置圆角弧度
          },
          // data: [getPct(currentIndex)],
          data: [100],
          itemStyle: {
            color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
              {
                offset: 0,
                color: '#1296db'
              },
              {
                offset: 1,
                color: '#91D5FF'
              }
            ]),
            borderRadius: [40, 40, 40, 40] // 设置圆角弧度
          }
        }
      ]
    })

    window.onresize = function () {
      //自适应大小
      chartInstance.resize()
    }

    if (parseFloat(echartsData.value[currentIndex]) === 2.98) {
      clearInterval(timer)
      return
    }

    setTimeout(() => {
      currentIndex++
      initChart()
    }, 1000)

    // console.log('currentIndex', currentIndex)
  }
}

timer = setInterval(initChart, 1000)

function initChartLine () {
  if (echartsShow.value === false) {
    // 当 echartsData 的长度为 0 时，直接停止定时器
    clearInterval(timer1)
    echartsData.value.push('0')
    return
  } else {
    if (currentIndex1 >= echartsData.value.length) {
      // 达到最后一个数据时停止定时器
      clearInterval(timer1)
      return
    }

    const chartDom = document.getElementById('myLineEcharts')
    if (chartInstance1) {
      // 在初始化图表之前，可能已经存在一个使用相同 DOM 元素的图表实例 , 会报警告"[ECharts] There is a chart instance already initialized on the dom."
      chartInstance1.dispose()
    }

    chartInstance1 = echarts.init(chartDom)

    chartInstance1.setOption({
      backgroundColor: '#fff',
      grid: {
        left: '5%',
        right: '10%',
        top: '20%',
        bottom: '15%',
        containLabel: true
      },
      tooltip: {
        show: true,
        trigger: 'axis',
        formatter: function (params) {
          return (
            '<span style="font-weight:bold">' +
            'epoch : ' +
            '<span style="font-weight:bold">' +
            params[0].name +
            '</span>' +
            '<br/>' +
            '<span style="font-weight:bold">' +
            params[0].seriesName +
            ' : </span>' +
            '<span style="font-weight:bold;color:#23D0C4">' +
            params[0].value +
            '</span>'
          )
        },
        rich: {
          value: {
            fontWeight: 'bold'
          }
        }
      },

      legend: {
        show: true,
        x: '75%',
        y: '5',
        icon: 'stack',
        itemWidth: 15,
        itemHeight: 10,
        textStyle: {
          color: '#646464'
        },
        data: ['loss']
      },
      xAxis: [
        {
          type: 'category',
          name: 'epoch数值',

          boundaryGap: 1,
          axisLine: {
            show: false
          },
          axisLabel: {
            color: '#A1A7B3'
          },
          splitLine: {
            show: false
          },
          axisTick: {
            show: false
          },
          data: newArray.value

          // data: [
          //   '10%',
          //   '20%',
          //   '30%',
          //   '40%',
          //   '50%',
          //   '60%',
          //   '70%',
          //   '80%',
          //   '90%',
          //   '100%'
          // ]
        }
      ],
      yAxis: [
        {
          type: 'value',
          name: 'loss数值',
          padding: 5,
          splitLine: {
            show: true,
            lineStyle: {
              color: '#A1A7B3',
              type: 'dashed'
            }
          },
          axisLine: {
            show: false
          },
          axisLabel: {
            show: true,
            margin: 10,
            textStyle: {
              color: '#A1A7B3'
            }
          },
          axisTick: {
            show: false
          }
        }
      ],
      series: [
        {
          name: 'loss',
          type: 'line',
          smooth: true,
          stack: '总量',
          symbolSize: 0,
          itemStyle: {
            normal: {
              color: '#23D0C4',
              lineStyle: {
                color: '#23D0C4',
                width: 2
              }
            }
          },
          areaStyle: {
            normal: {
              color: new echarts.graphic.LinearGradient(
                0,
                0,
                0,
                1,
                [
                  {
                    offset: 0,
                    color: 'rgba(50, 216, 205, 1)'
                  },
                  {
                    offset: 1,
                    color: 'rgba(35, 208, 196, 0.4)'
                  }
                ],
                false
              )
            }
          },
          data: lossData.value
        }
      ]
    })

    window.onresize = function () {
      //自适应大小
      chartInstance1.resize()
    }

    if (parseFloat(echartsData.value[currentIndex1]) === 2.98) {
      clearInterval(timer1)
      return
    }

    setTimeout(() => {
      currentIndex1++
      initChart()
    }, 1000)

    // console.log('currentIndex', currentIndex)
  }
}

timer1 = setInterval(initChartLine, 1000)

// 关闭echarts时销毁实例
onUnmounted(() => {
  if (chartInstance) {
    chartInstance.dispose()
  }

  if (chartInstance1) {
    chartInstance1.dispose()
  }
  closeWebSocket()
})
</script>

<style lang="less" scoped>
.deploy {
  padding: 30px 60px 0 60px;

  .cardTop {
    margin-bottom: 30px;
    color: #27264d;
    font-size: 32px;
    opacity: 0.85;
    display: flex;
  }
  .elCard {
    .left {
      width: 300px;
      .leftUl {
        img {
          width: 20px;
          height: 20px;
        }
        .text {
          margin-left: 15px;
          color: #27264d;
          font-weight: 500;
          font-size: 16px;
          line-height: 24px;
          letter-spacing: 0;
          opacity: 0.85;
          height: 35px;
        }
        .chatImg {
          padding-left: 10px;
          img {
            width: 35px;
            height: 35px;
          }
        }

        .leftLi {
          display: flex;
          .circle {
            position: relative;
          }
          .circle::after {
            content: '';
            position: absolute;
            top: 37%;
            left: 50%;
            transform: translate(-50%, 0);
            width: 2px;
            height: var(--circle-height, 485px);
            background-color: #75b7ff;
          }
        }
        .leftLi1-5 {
          display: flex;
          margin-top: 140px;
          align-items: center;
          .textBottom {
            padding-left: 10px;
            color: rgba(112, 114, 121, 0.85);
            cursor: pointer;
            img {
              width: 15px;
              height: 12px;
            }
          }
        }
        .leftLi2 {
          display: flex;
          margin-top: 270px;
          align-items: center;
          .textBottom {
            padding-left: 10px;
            height: 30px;
            color: rgba(112, 114, 121, 0.85);
            cursor: pointer;
            img {
              width: 15px;
              height: 12px;
            }
          }
        }
        .leftLi3 {
          display: flex;
          .circle3 {
            position: relative;
            top: var(--circle-top, 20px);
            opacity: var(--opacity, 0);
          }
        }
        .isCreateTrue {
          --circle-height: 580px;
          --circle-top: 60px;
          --opacity: 1;
        }
      }
    }
    .elForm {
      width: 1000px;

      .conent {
        // display: flex;
        width: 1500px;
        .echartsLine {
          height: var(--height, 30px);
          width: 80%;
          #myLineEcharts {
            height: var(--height, 30px);
            width: 100%;
            padding-bottom: 30px;
          }
        }
        .echarts {
          height: var(--height, 30px);
          width: 80%;
          #myEcharts {
            height: var(--height, 30px);
            width: 100%;
          }
        }
        .isEchartsTrue {
          --height: 65px;
        }

        .isEchartsLineTrue {
          --height: 250px;
        }

        .logs {
          width: 80%;
          height: 500px;
          margin-top: var(--margin-top, -50px);
          overflow: auto;
          border: 2px solid #ccc;
          border-radius: 7px;
          .echartsMsg {
            display: flex;
          }
        }
        .isCreateTrue {
          --margin-top: 30px;
        }
      }

      :deep(.el-select) {
        width: 100%;
      }
      .elButton {
        :deep(.el-form-item__content) {
          display: flex;
          justify-content: space-evenly;
          margin-top: 20px;
        }
      }
    }
  }

  :deep(.el-card__body) {
    display: flex;
  }
  :deep(.toCreate) {
    margin-top: 20px;
  }

  :deep(.el-input__inner) {
    white-space: pre-wrap;
    word-break: break-all;
    height: 30px;
  }
}
</style>
